<template>
    <div class="root">
        <div class="container-shell">
            <div class="container-shell-title">jessibuca Pro demo player <span class="tag-version" v-if="version">({{
                    version
                }})</span></div>
            <div id="container"></div>
            <div class="input input-annnie">
                <div style="color: red" class="input-tips">Tips:支持录制MP4(MPEG-4)格式的视频(仅录制视频，不包含音频)
                </div>
            </div>
            <div class="input input-annnie">
                <div style="color: red" class="input-tips">Tips:支持录制FLV格式的视频(视频+音频)
                </div>
            </div>
            <div class="input input-annnie">
                <div style="color: green" class="input-tips">Tips:<a href="/pro-module.html">MP4录制扩展模块</a>支持(视频H264/H265+音频AAC,MP3,G711a/u)
                </div>
            </div>
            <div class="input input-wrap">
                <div>
                    当前浏览器：
                    <span v-if="supportMSE" style="color: green;margin-right: 10px">支持MSE H264解码；</span>
                    <span v-if="!supportMSE" style="color: red;">不支持MSE H264解码；</span>
                    <span v-if="supportMSEHevc" style="color: green;margin-right: 10px">支持MSE H265解码;</span>
                    <span v-if="!supportMSEHevc" style="color: red;margin-right: 10px;">不支持MSE H265解码,会自动切换成wasm(simd)解码</span>
                    <span v-if="!isEdgeSupportHevc"><a style="color:blue"
                                                       href="https://jessibuca.com/zip/Microsoft.HEVCVideoExtension_2.1.1803.0_neutra.zip"
                                                       target="_blank">下载window Edge Hevc扩展插件</a></span>
                </div>
                <div>
                    <div v-if="playing && decodeType">
                        当前解码：<span>{{ decodeType }}</span>
                    </div>
                    <div v-if="playing && renderType">
                        当前模式：<span>{{ playType }}</span> 当前渲染：<span>{{ renderType }}</span>
                    </div>
                </div>
            </div>
            <div class="input">
                当前浏览器：
                <span v-if="supportWCS" style="color: green;">支持Webcodec H264解码；</span>
                <span v-if="!supportWCS" style="color: red;">不支持Webcodec H265解码(需要https/localhost),</span>
                <span v-if="supportWCSHevc" style="color: green;">支持Webcodec H265解码；</span>
                <span v-if="!supportWCSHevc" style="color: red;">不支持Webcodec H265解码(需要https/localhost),会自动切换成wasm(simd)解码</span>
            </div>
            <div class="input">
                当前浏览器：
                <span v-if="supportSIMDHevc" style="color: green;">支持SIMD解码；</span>
                <span v-else style="color: red;">不支持SIMD解码,会自动切换成wasm解码；</span>

                <span v-if="supportMT" style="color: green;">支持wasm,wasm(SIMD)多线程解码；</span>
                <span v-else style="color: red;">不支持wasm,wasm(SIMD)多线程解码； <a style="color: blue"
                                                                                     href="/pro-doc.html#localhost">多线程开启方式</a> </span>
            </div>
            <div class="input">
                当前浏览器：
                <span v-if="supportWebgpu" style="color: green;">支持webgpu渲染</span>
                <span v-else style="color: red;">不支持webgpu渲染,会自动切换成webgl渲染</span>（适用于wasm(simd)解码+canvas渲染）
            </div>
            <div class="input">
                <span>最大网络延迟:</span>
                <input
                    style="width: 50px"
                    type="number"
                    v-model="networkDelay"
                    @change="changeNetworkDelay"
                /><span style="margin-right: 5px">秒</span>
                <span>最大延迟:</span>
                <input
                    style="width: 50px"
                    type="number"
                    v-model="videoBufferDelay"
                    @change="changeBufferDelay"
                /><span style="margin-right: 5px">秒</span>
                <span>缓冲:</span>
                <input
                    style="width: 50px"
                    type="number"
                    v-model="videoBuffer"
                    @change="changeBuffer"
                /><span style="margin-right: 5px">秒</span>


            </div>
            <div class="input">
                <span>硬解码：</span>
                <input
                    type="checkbox"
                    v-model="useMSE"
                    @change="restartPlay('mse')"
                /><span>MediaSource</span>
                <input
                    type="checkbox"
                    v-model="useWCS"
                    @change="restartPlay('wcs')"
                /><span>webcodecs</span> |
                <input
                    checked
                    @change="restartPlay()"
                    type="checkbox"
                    v-model="audioDecodeUseHardware"
                />
                <span>硬解码音频</span>
            </div>
            <div class="input">
                <span>软解码：</span>
                <input
                    type="checkbox"
                    v-model="useSIMD"
                    @change="restartPlay('simd')"
                /><span>SIMD</span>
                <input
                    type="checkbox"
                    v-model="isFFmpegSIMD"
                    @change="restartPlay('simd')"
                /><span>isSIMD(V2)</span>
            </div>
            <div class="input">
                <input
                    v-model="demuxUseWorker"
                    type="checkbox"
                    @change="restartPlay()"
                /><span>硬解码(MediaSource，Webcodec)worker解封装</span>
                <input
                    v-model="mseDecoderUseWorker"
                    type="checkbox"
                    @change="restartPlay()"
                /><span>硬解码(MediaSource)worker解码</span>
            </div>
            <div class="input">
                <div>
                    <div v-if="supportMT" style="display: inline-block">
                        <input

                            type="checkbox"
                            v-model="useMT"
                            @change="restartPlay()"
                        /><span>使用多线程解码</span>
                    </div>
                    <input
                        type="checkbox"
                        v-model="isMute"
                        @change="restartPlay()"
                    /><span>静音播放</span>

                    <input
                        type="checkbox"
                        v-model="decoderErrorAutoWasm"
                        @change="restartPlay()"
                    /><span>硬解码失败降级到wasm</span>
                </div>
            </div>
            <div class="input">
                <input
                    type="checkbox"
                    v-model="isFlv"
                    @change="restartPlay('isFlv')"
                /><span>设置Flv格式</span>
                <input
                    type="checkbox"
                    v-model="isHls"
                    @change="restartPlay('isHls')"
                /><span>设置Hls格式</span>
                <input
                    type="checkbox"
                    v-model="isFmp4"
                    @change="restartPlay('isFmp4')"
                /><span>设置Fmp4格式</span>
                <input
                    type="checkbox"
                    v-model="isTs"
                    @change="restartPlay('isTs')"
                /><span>设置Mpeg-ts格式</span>
                <input
                    type="checkbox"
                    v-model="isPs"
                    @change="restartPlay('isPs')"
                /><span>设置Mpeg(PS)格式</span>
                <input
                    type="checkbox"
                    v-model="isNakedFlow"
                    @change="restartPlay('isNakedFlow')"
                /><span>设置裸流格式</span>
            </div>
            <div class="input">
                <input
                    type="checkbox"
                    v-model="networkDelayTimeoutReplay"
                    @change="restartPlay()"
                /><span>网络延迟重新播放</span>
                <input
                    type="checkbox"
                    v-model="hiddenAutoPause"
                    @change="restartPlay()"
                /><span>最小化自动暂停</span>
                <input
                    type="checkbox"
                    v-model="hasVideo"
                    @change="restartPlay()"
                /><span>解码视频</span>
                <input
                    type="checkbox"
                    v-model="hasAudio"
                    @change="restartPlay()"
                /><span>解码音频</span>
                <input
                    type="checkbox"
                    v-model="checkFirstIFrame"
                    @change="restartPlay()"
                /><span>检查首帧是否I帧（wasm软解码支持）</span>
            </div>
            <div class="input">
                <span>渲染标签：</span>
                <select v-model="renderDom" @change="renderDomChange">
                    <option value="video">video</option>
                    <option value="canvas">canvas</option>
                </select>
                <template v-if="renderDom === 'canvas'">
                    <span>渲染引擎：</span>
                    <select v-model="canvasRenderType" @change="renderDomChange">
                        <option value="webgl">webgl</option>
                        <option value="webgpu">webgpu</option>
                    </select>
                </template>
                <span>音频引擎：</span>
                <select v-model="audioEngine" @change="replay">
                    <option value="">自动</option>
                    <option value="worklet">worklet(https)</option>
                    <option value="script">script(默认)</option>
                    <option value="active">active(安卓)</option>
                </select>
                <span class="span-row" style="margin-left: 10px">
                    <span style="color:red;">录制格式</span>
                    <select v-model="recordType" @change="restartPlay()">
                        <option value="webm">webm</option>
                        <option value="mp4">mp4</option>
                    </select>
                </span>
                <input
                    type="checkbox"
                    v-model="isDebug"
                    ref="isDebug"
                    @change="restartPlay"
                /><span>控制台日志</span>
                <span class="span-row" v-if="isDebug" style="margin-left: 10px">
                    <span style="color:red;">日志等级</span>
                    <select v-model="debugLevel" @change="restartPlay()">
                        <option value="debug">debug</option>
                        <option value="warn">warn</option>
                    </select>
                </span>
            </div>
            <div class="input">

                <div style="line-height: 30px">
                    <input
                        type="checkbox"
                        v-model="showOperateBtns"
                        @change="restartPlay"
                    /><span>操作按钮</span>
                    <input
                        type="checkbox"
                        v-model="showBandwidth"
                        @change="restartPlay"
                    /><span>网速</span>
                    <input
                        type="checkbox"
                        v-model="hotKey"
                        @change="restartPlay()"
                    /><span>键盘快捷键</span>
                    <input
                        type="checkbox"
                        v-model="controlAutoHide"
                        @change="restartPlay()"
                    /><span>控制栏自动隐藏</span>
                    <input
                        type="checkbox"
                        v-model="syncAudioAndVideo"
                        @change="restartPlay()"
                    /><span>音视频同步</span>
                    <input
                        type="checkbox"
                        v-model="isDropSameTimestampGop"
                        @change="restartPlay()"
                    /><span>遇到相同时间戳是否丢gop</span>
                    <input
                        type="checkbox"
                        v-model="showPerformance"
                        @change="togglePerformance"
                    /><span>显示性能面板</span>
                </div>
            </div>
            <div class="input">
                <div>
                    <button @click="toggleControlBar">toggle控制条</button>
                    <a href="/test-url.html" target="_blank" style="color: red;margin-left: 10px">测试地址(包含VR测试地址)</a>
                </div>
            </div>
            <div class="input">
                <div>输入URL：</div>
                <input
                    placeholder="支持 hls/ws-raw/ws-flv/http-flv/fmp4/mpeg-ts/mpeg(ps)/webrtc/Aliyun-rtc/裸流/等协议"
                    type="input"
                    autocomplete="on"
                    v-model="playUrl"
                />

            </div>
            <div class="input">
                <div>
                    <template v-if="!playing">
                        <button v-if="playType === '' || playType === 'play'" @click="play">播放直播流</button>
                        <button v-if="playType === '' || playType === 'playback'" @click="playback">播放录像流</button>
                        <button v-if="playType === '' || playType === 'playVod'" @click="playVod">播放点播文件</button>
                        <button v-if="playType === '' || playType === 'playVR'" @click="playVR">播放VR文件</button>
                    </template>
                    <template v-if="loading || playing">
                        <template v-if="playType === 'play'">
                            <button @click="()=> pause()">停止</button>
                            <button @click="()=> pause(true)">停止(清屏)</button>
                        </template>
                        <button v-if="playType === 'playback'" @click="pause">停止录像流</button>
                    </template>
                </div>
            </div>


            <div class="input" style="line-height: 30px">
                <button @click="destroyPlayer">销毁</button>
                <template v-if="loaded">
                    <button v-if="quieting" @click="cancelMute">取消静音</button>
                    <template v-else>
                        <button @click="mute">静音</button>
                        <span>音量：</span>
                        <select v-model="volume" @change="volumeChange">
                            <option value="1">100</option>
                            <option value="0.75">75</option>
                            <option value="0.5">50</option>
                            <option value="0.25">25</option>
                        </select>
                    </template>
                    <span>旋转：</span>
                    <select v-model="rotate" @change="rotateChange">
                        <option value="0">0</option>
                        <option value="90">90</option>
                        <option value="18">180</option>
                        <option value="270">270</option>
                    </select>
                    <span>镜像旋转:</span>
                    <select v-model="mirrorRotate" @change="mirrorRotateChange">
                        <option value="none">无</option>
                        <option value="level">水平</option>
                        <option value="vertical">垂直</option>
                    </select>

                    <button @click="fullscreen">全屏</button>
                    <button @click="screenShot">截图</button>
                    <button @click="screenshotWatermark1">截图(水印文字)</button>
                    <button @click="screenshotWatermark2">截图(水印图片)</button>
                    <template v-if="playType === 'playback'">
                        <span>切换播放倍率:</span>
                        <select v-model="playbackRate" @change="playbackRateChange">
                            <option value="1">1倍</option>
                            <option value="2">2倍</option>
                            <option value="3">3倍</option>
                            <option value="4">4倍</option>
                        </select>

                    </template>
                </template>
            </div>
            <div class="input" v-if="loaded">
                <button @click="screenShot">截图</button>
                <button @click="screenShotBlob">截图(Blob)</button>
                <button @click="screenShotBase64">截图(base64)</button>
                <button @click="screenshotWatermark1">截图(水印文字)</button>
                <button @click="screenshotWatermark1Blob">截图(水印文字)(Blob)</button>
                <button @click="screenshotWatermark2">截图(水印图片)</button>
                <button @click="screenshotWatermark2Blob">截图(水印图片)(Blob)</button>
            </div>
            <div class="input" v-if="loaded">
                <select v-model="scale" @change="scaleChange">
                    <option value="0">完全填充(拉伸)</option>
                    <option value="1">等比缩放</option>
                    <option value="2">完全填充(未拉伸)</option>
                </select>
                <button v-if="!playing" @click="clearView">清屏</button>
                <template v-if="playing">
                    <!--                    <select v-model="recordType">-->
                    <!--                        <option value="webm">webm</option>-->
                    <!--                        <option value="mp4">mp4</option>-->
                    <!--                    </select>-->
                    <button v-if="!recording" @click="startRecord">录制</button>
                    <button v-if="!recording" @click="stopAndSaveRecord">暂停录制(下载)</button>
                    <button v-if="!recording" @click="stopAndSaveRecord2">暂停录制(blob)</button>
                </template>
                <button @click="clearBufferDelay">手动消除延迟</button>
                <input
                    type="checkbox"
                    v-model="toggleZoom"
                    @change="toggleZoomOperate"
                /><span>切换电子放大</span>
            </div>
            <div class="input" v-if="loaded">
                <span style="color: red">画框（文字）（随机坐标）</span>：
                <button @click="handleAddCanvas('text')">文本</button>
                <button @click="handleAddCanvas('rect')">框子</button>
                <button @click="handleAddCanvas('rect+text')">文本+框子</button>
                <button @click="handleAddCanvasClean()">清空</button>
            </div>
        </div>
    </div>
</template>
<script>
import {ElNotification, ElMessage} from 'element-plus'

function getBrowser() {
    const UserAgent = window.navigator.userAgent.toLowerCase() || '';
    const browserInfo = {};
    const browserArray = {
        IE: window.ActiveXObject || "ActiveXObject" in window, // IE
        Chrome: UserAgent.indexOf('chrome') > -1 && UserAgent.indexOf('safari') > -1, // Chrome浏览器
        Firefox: UserAgent.indexOf('firefox') > -1, // 火狐浏览器
        Opera: UserAgent.indexOf('opera') > -1, // Opera浏览器
        Safari: UserAgent.indexOf('safari') > -1 && UserAgent.indexOf('chrome') == -1, // safari浏览器
        Edge: UserAgent.indexOf('edge') > -1, // Edge浏览器
        QQBrowser: /qqbrowser/.test(UserAgent), // qq浏览器
        WeixinBrowser: /MicroMessenger/i.test(UserAgent) // 微信浏览器
    };
    // console.log(browserArray)
    for (let i in browserArray) {
        if (browserArray[i]) {
            let versions = '';
            if (i === 'IE') {
                const versionArray = UserAgent.match(/(msie\s|trident.*rv:)([\w.]+)/)
                if (versionArray && versionArray.length > 2) {
                    versions = UserAgent.match(/(msie\s|trident.*rv:)([\w.]+)/)[2];
                }
            } else if (i === 'Chrome') {
                for (let mt in navigator.mimeTypes) {
                    //检测是否是360浏览器(测试只有pc端的360才起作用)
                    if (navigator.mimeTypes[mt]['type'] === 'application/360softmgrplugin') {
                        i = '360';
                    }
                }
                const versionArray = UserAgent.match(/chrome\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            } else if (i === 'Firefox') {
                const versionArray = UserAgent.match(/firefox\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            } else if (i === 'Opera') {
                const versionArray = UserAgent.match(/opera\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            } else if (i === 'Safari') {
                const versionArray = UserAgent.match(/version\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            } else if (i === 'Edge') {
                const versionArray = UserAgent.match(/edge\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            } else if (i === 'QQBrowser') {
                const versionArray = UserAgent.match(/qqbrowser\/([\d.]+)/);
                if (versionArray && versionArray.length > 1) {
                    versions = versionArray[1];
                }
            }
            browserInfo.type = i;
            browserInfo.version = parseInt(versions);
        }
    }
    return browserInfo;
}

function formatTimeTips(time) {
    var result;

    time = parseInt(time / 1000, 10);
    //
    if (time > -1) {
        var hour = Math.floor(time / 3600);
        var min = Math.floor(time / 60) % 60;
        var sec = time % 60;

        sec = Math.round(sec);

        if (hour < 10) {
            result = '0' + hour + ":";
        } else {
            result = hour + ":";
        }

        if (min < 10) {
            result += "0";
        }
        result += min + ":";
        if (sec < 10) {
            result += "0";
        }
        result += sec.toFixed(0);
    }

    return result;
}

function toString(value) {
    const nativeToString = Object.prototype.toString;

    function isErrorLike(error) {
        switch (nativeToString.call(error)) {
            case '[object Error]':
                return true;
            case '[object Exception]':
                return true;
            case '[object DOMException]':
                return true;
            default:
                try {
                    return error instanceof Error;
                } catch (e) {
                    return false;
                }
        }
    }

    if (isErrorLike(value)) {
        return value.toString();
    }

    return value == null
        ? '' :
        typeof value === 'object'
            ? JSON.stringify(value, null, 2)
            : String(value)
}

function isMobile() {
    return (/iphone|ipad|android.*mobile|windows.*phone|blackberry.*mobile/i.test(window.navigator.userAgent.toLowerCase()));
}

function isPad() {
    return (/ipad|android(?!.*mobile)|tablet|kindle|silk/i.test(window.navigator.userAgent.toLowerCase()));
}

export default {
    name: "ProDemoPlayer",
    jessibuca: null,
    vConsole: null,
    props: {},
    data() {
        return {
            playUrl: '',
            version: '',
            videoBuffer: 0.2,
            videoBufferDelay: 1,
            networkDelay: 10,
            wasm: false,
            playing: false,
            quieting: true,
            loading: false,
            loaded: false, // mute
            isMute: false, // 是否静音
            showOperateBtns: true,
            showBandwidth: true,
            hotKey: false,
            err: "",
            speed: 0,
            performance: "",
            fps: '',
            dfps: '',
            volume: 1,
            rotate: 0,
            mirrorRotate: 'none',
            supportMSEHevc: false,
            supportMSE: false,
            supportWCS: false,
            supportWCSHevc: false,
            supportSIMDHevc: false,
            supportMT: false,
            supportWebgpu: false,
            useWCS: false,
            useMSE: false,
            useSIMD: true,
            audioDecodeUseHardware: true,
            isFFmpegSIMD: true,
            useMT: true,
            useOffscreen: false,
            networkDelayTimeoutReplay: false,
            recording: false,
            isDebug: true,
            recordType: 'mp4',
            debugLevel: 'debug',
            scale: 0,
            playType: '',
            decodeType: '',
            renderType: '',
            renderDom: 'video',
            canvasRenderType: 'webgl',
            audioEngine: '',
            playingTimestamp: '',
            dts: '',
            stats: {},
            videoInfo: {},
            audioInfo: {},
            playbackRate: 1,
            playModel: 'video+audio',
            isFlv: false,
            isFmp4: false,
            isHls: false,
            isTs: false,
            isPs: false,
            isNakedFlow: false,
            decoderErrorAutoWasm: true,
            hiddenAutoPause: false,
            hasVideo: true,
            hasAudio: true,
            controlAutoHide: true,
            syncAudioAndVideo: true,
            showMsg: true,
            showPerformance: true,
            toggleZoom: false,
            talkVolume: 100,
            talkEncType: 'g711a',
            talkPacketType: 'rtp',
            talkSampleRate: 16000,
            talkSampleBitsWidth: 16,
            talkUrl: '',
            checkFirstIFrame: true,
            isDropSameTimestampGop: false,
            demuxUseWorker: true,
            mseDecoderUseWorker: false,
            isEdgeSupportHevc: false,// 默认
        };
    },
    mounted() {
        if (window.VConsole && (isMobile() || isPad())) {
            this.vConsole = new window.VConsole();
        }
        this.supportMSEHevc = window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="hev1.1.6.L123.b0"');
        this.supportMSE = ('MediaSource' in self) || ('ManagedMediaSource' in self);
        this.supportWCS = "VideoEncoder" in window;
        this.supportWebgpu = 'gpu' in navigator;
        const browserInfo = getBrowser();
        this.supportWCSHevc = browserInfo.type.toLowerCase() === 'chrome' && browserInfo.version >= 107 && (location.protocol === 'https:' || location.hostname === 'localhost');
        this.supportSIMDHevc = WebAssembly && WebAssembly.validate(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11]));
        this.isEdgeSupportHevc = browserInfo.type.toLowerCase() === 'edge' && (this.supportMSEHevc || this.supportWCSHevc);

        this.supportMT = typeof SharedArrayBuffer !== 'undefined';
        this.create();
        window.onerror = (msg) => (this.err = msg);
    },
    async unmounted() {
        if (this.jessibuca) {
            await this.jessibuca.destroy()
            this.jessibuca = null
        }
        if (this.vConsole) {
            this.vConsole.destroy();
        }
    },
    methods: {
        create(options) {
            options = options || {};
            const jessibuca = new window.JessibucaPro(
                Object.assign(
                    {
                        container: document.getElementById('container'),
                        decoder: '/pro/js/decoder-pro.js',
                        videoBuffer: Number(this.videoBuffer), // 缓存时长
                        videoBufferDelay: Number(this.videoBufferDelay),
                        isResize: false,
                        useWCS: this.useWCS,
                        decoderErrorAutoWasm: this.decoderErrorAutoWasm,
                        mseDecodeAudio: this.audioDecodeUseHardware,
                        wcsDecodeAudio: this.audioDecodeUseHardware,
                        useMSE: this.useMSE,
                        useSIMD: this.useSIMD,
                        isFFmpegSIMD: this.isFFmpegSIMD,
                        useMThreading: this.useMT,
                        wcsUseVideoRender: this.useWCS,
                        loadingIcon: true,
                        syncAudioAndVideo: this.syncAudioAndVideo,
                        text: "",
                        // background: "bg.jpg",
                        loadingText: "Jessibuca pro 疯狂加载中...",
                        // hasAudio:false,
                        debug: this.isDebug,
                        debugLevel: this.debugLevel,
                        hotKey: this.hotKey,
                        // hasAudio:false,
                        supportDblclickFullscreen: true,
                        showBandwidth: this.showBandwidth, // 显示网速
                        qualityConfig: ['普清', '高清', '超清', '4K', '8K'],
                        operateBtns: {
                            fullscreen: this.showOperateBtns,
                            screenshot: this.showOperateBtns,
                            record: this.showOperateBtns,
                            play: this.showOperateBtns,
                            audio: this.showOperateBtns,
                            ptz: this.showOperateBtns,
                            quality: this.showOperateBtns,
                            close: this.showOperateBtns,
                            zoom: this.showOperateBtns,
                            performance: this.showOperateBtns,
                            scale: this.showOperateBtns
                        },
                        extendOperateBtns: [
                            {
                                name: 'testBtn',
                                index: 2,
                                icon: '/expand.png',
                                iconHover: '/expand-hover.png',
                                iconTitle: '测试hover',
                                activeIcon: '/zoom-stop.png',
                                activeIconHover: '/zoom-stop-hover.png',
                                activeIconTitle: '测试active-hover',
                                click: () => {
                                    ElMessage.success('点击了test按钮');
                                },
                                activeClick: () => {
                                    ElMessage.success('点击了test按钮 active状态')
                                },
                            },
                        ],
                        isFlv: this.isFlv,
                        isFmp4: this.isFmp4,
                        isHls: this.isHls,
                        isNakedFlow: this.isNakedFlow,
                        hiddenAutoPause: this.hiddenAutoPause,
                        forceNoOffscreen: !this.useOffscreen,
                        isNotMute: !this.isMute,
                        hasAudio: this.hasAudio,
                        hasVideo: this.hasVideo,
                        controlAutoHide: this.controlAutoHide,
                        timeout: 10,
                        useVideoRender: this.renderDom === 'video',
                        useCanvasRender: this.renderDom === 'canvas',
                        networkDelayTimeoutReplay: false,
                        playbackForwardMaxRateDecodeIFrame: 8,
                        checkFirstIFrame: this.checkFirstIFrame,
                        watermarkConfig: {
                            image: {
                                // src: 'http://jessibuca.monibuca.com/jessibuca-logo.png',
                                src: '',
                                width: 150,
                                height: 48
                            },
                            // text:{
                            //     content:'jessibuca-pro'
                            // },
                            right: 10,
                            top: 30
                        },
                        contextmenuBtns: [
                            {
                                content: '切换性能面板',
                                index: 1,
                                click: () => {
                                    const playStatus = this.jessibuca.getStatus()
                                    if (playStatus === 'playing') {
                                        this.jessibuca.togglePerformancePanel();
                                    } else {
                                        ElMessage.warning('请先播放视频');
                                    }
                                }
                            },
                            {
                                content: '关于PRO',
                                index: 2,
                                click: () => {
                                    ElMessage.success('如需要购买PRO版本可以联系添加作者微信：bosswancheng');
                                }
                            }
                        ],
                        showPerformance: this.showPerformance,
                        recordType: this.recordType,
                        ptzZoomShow: true,
                        ptzMoreArrow: true,
                        ptzApertureShow: true,
                        ptzFocusShow: true,
                        controlHtml: '<div style="color: red">这个是自定义HTML</div>',
                        useWebGPU: this.canvasRenderType === 'webgpu',
                        isDropSameTimestampGop: this.isDropSameTimestampGop,
                        demuxUseWorker: this.demuxUseWorker,
                        mseDecoderUseWorker: this.mseDecoderUseWorker,
                    },
                    options
                )
            );

            this.jessibuca = jessibuca;
            let configOptions = jessibuca.getOption();
            var _this = this;
            jessibuca.on(JessibucaPro.EVENTS.load, (msg) => {
                !this.isDebug && console.log("on load");
            });

            jessibuca.on(JessibucaPro.EVENTS.log, (msg) => {
                !this.isDebug && console.log("on log", msg);
            });
            jessibuca.on(JessibucaPro.EVENTS.recordingTimestamp, (msg) => {
                !this.isDebug && console.log("on record:", msg);
            });
            jessibuca.on(JessibucaPro.EVENTS.recordingTimestamp.pause, (msg) => {
                !this.isDebug && console.log("on pause");
                this.playing = false;
            });
            jessibuca.on(JessibucaPro.EVENTS.play, (msg) => {
                !this.isDebug && console.log("on play");
                this.playing = true;
            });
            jessibuca.on(JessibucaPro.EVENTS.fullscreen, (msg) => {
                !this.isDebug && console.log("on fullscreen", msg);
            });

            jessibuca.on(JessibucaPro.EVENTS.mute, (msg) => {
                !this.isDebug && console.log("on mute", msg);
                this.quieting = msg;
            });

            jessibuca.on(JessibucaPro.EVENTS.mute, (msg) => {
                !this.isDebug && console.log("on mute2", msg);
            });

            jessibuca.on(JessibucaPro.EVENTS.audioInfo, (msg) => {
                !this.isDebug && console.log("audioInfo", msg);
                this.audioInfo = Object.assign({}, msg)
            });

            jessibuca.on(JessibucaPro.EVENTS.kBps, (msg) => {
                // console.log('bps', bps);
            });

            jessibuca.on(JessibucaPro.EVENTS.videoInfo, (info) => {
                !this.isDebug && console.log("videoInfo", info);
                this.videoInfo = info;
            });

            jessibuca.on(JessibucaPro.EVENTS.error, (error) => {
                !this.isDebug && console.log("error", error);
            });

            jessibuca.on(JessibucaPro.EVENTS.timeout, () => {
                !this.isDebug && console.log("timeout");
            });

            jessibuca.on(JessibucaPro.EVENTS.start, () => {
                !this.isDebug && console.log('frame start');

                const decodeType = jessibuca.getDecodeType();
                this.decodeType = decodeType;

                const renderType = jessibuca.getRenderType();
                this.renderType = renderType;
                // setTimeout(() => {
                //     this.screenshotWatermark1Blob();
                // }, 100);
            })

            jessibuca.on(JessibucaPro.EVENTS.performance, (performance) => {
                var show = "卡顿";
                if (performance === 2) {
                    show = "非常流畅";
                } else if (performance === 1) {
                    show = "流畅";
                }
                this.performance = show;
            });
            jessibuca.on('buffer', (buffer) => {
                !this.isDebug && console.log('buffer', buffer);
            })

            jessibuca.on(JessibucaPro.EVENTS.stats, (stats) => {
                !this.isDebug && console.log('stats', stats);
            })

            jessibuca.on(JessibucaPro.EVENTS.play, () => {
                this.playing = true;
                this.loaded = true;
                this.loading = false;
                this.quieting = jessibuca.isMute();
            });

            jessibuca.on(JessibucaPro.EVENTS.recordingTimestamp, (ts) => {
                !this.isDebug && console.log('recordingTimestamp: ', ts);
            })

            jessibuca.on(JessibucaPro.EVENTS.playToRenderTimes, (times) => {
                !this.isDebug && console.log('playToRenderTimes: ', times);
            })

            jessibuca.on(JessibucaPro.EVENTS.ptz, (arrow) => {
                console.log('ptz arrow', arrow);
            })

            jessibuca.on(JessibucaPro.EVENTS.crashLog, (log) => {
                console.error('crashLog', log)
            })

            jessibuca.on(JessibucaPro.EVENTS.playFailedAndPaused, (error) => {
                jessibuca.showErrorMessageTips('播放异常：' + error);
            })


            jessibuca.on('performance', (performance) => {
                !this.isDebug && console.log('performance: ', performance);
            })

            jessibuca.on('playbackPauseOrResume', (value) => {
                !this.isDebug && console.log('playbackPauseOrResume: ', value);
            })

            //
            jessibuca.on('crashLog', (value) => {
                console.error('crashLog: ', value);
                ElNotification.error({
                    title: '错误',
                    message: JSON.stringify(value)
                });
            })

            jessibuca.on('close', () => {
                !this.isDebug && console.log('jessibuca close');
                setTimeout(() => {
                    this.initPlayer();
                    this.playType = '';
                }, 1000)


            })

            // this.play();
            // console.log(this.jessibuca);
        },
        play() {
            // this.jessibuca.onPlay = () => (this.playing = true);


            if (this.playUrl) {
                this.jessibuca.play(this.playUrl).then(() => {
                    ElMessage.success('play success');
                }).catch((err) => {
                    ElMessage.error('播放失败');
                    this.jessibuca.showErrorMessageTips('播放异常：' + err.toString());
                });
                this.playType = 'play'
                this.loading = true;
            } else {
                ElMessage.error('play url is empty')
                this.jessibuca.showErrorMessageTips('播放地址不能为空');
            }
        },
        playback() {
            const playList = [
                {"start": 1653840000, "end": 1653841624}, {
                    "start": 1653841634,
                    "end": 1653843420
                }, {"start": 1653843429, "end": 1653843958}, {"start": 1653843967, "end": 1653845688}, {
                    "start": 1653845698,
                    "end": 1653846480
                }, {"start": 1653846490, "end": 1653847199}, {"start": 1653847208, "end": 1653848531}, {
                    "start": 1653848541,
                    "end": 1653850863
                }, {"start": 1653850872, "end": 1653853371}, {"start": 1653853381, "end": 1653857885}, {
                    "start": 1653857894,
                    "end": 1653858352
                }, {"start": 1653858362, "end": 1653860545}, {"start": 1653860554, "end": 1653861080}, {
                    "start": 1653861090,
                    "end": 1653862017
                }, {"start": 1653862026, "end": 1653863812}, {"start": 1653863822, "end": 1653865325}, {
                    "start": 1653865335,
                    "end": 1653867374
                }, {"start": 1653867383, "end": 1653867698}, {"start": 1653867707, "end": 1653868816}, {
                    "start": 1653868826,
                    "end": 1653872829
                }, {"start": 1653872838, "end": 1653877527}, {"start": 1653877537, "end": 1653879799}, {
                    "start": 1653879809,
                    "end": 1653881953
                }, {"start": 1653881963, "end": 1653885397}, {"start": 1653885407, "end": 1653886894}, {
                    "start": 1653886904,
                    "end": 1653890591
                }, {"start": 1653890600, "end": 1653894360}, {"start": 1653894370, "end": 1653903276}, {
                    "start": 1653903286,
                    "end": 1653912848
                }, {"start": 1653912858, "end": 1653914424}, {"start": 1653914433, "end": 1653915002}, {
                    "start": 1653915011,
                    "end": 1653918125
                }, {"start": 1653918135, "end": 1653921622}, {"start": 1653921631, "end": 1653924609}, {
                    "start": 1653924618,
                    "end": 1653926399
                }]
            if (this.jessibuca.isPlaybackPaused()) {
                this.jessibuca.playbackResume()
            } else {
                if (this.playUrl) {
                    this.jessibuca.playback(this.playUrl, {
                        playList,
                        fps: 25,
                        isUseFpsRender: true,
                        showControl: true,
                        uiUsePlaybackPause: true,
                        isUseLocalCalculateTime: true,
                        useMSE: this.useMSE,
                        useWCS: this.useWCS,
                        useWasm: this.useWasm,
                        useSIMD: this.useSIMD,
                    }).then(() => {
                        ElMessage.success('playback success');
                    }).catch((e) => {
                        ElMessage.error(`playback error : ${toString(e)}`);
                    })
                    this.playType = 'playback'
                } else {
                    ElMessage.error('play url is empty')
                }
            }
        },

        playVod() {
            if (this.jessibuca.isPlayVodPaused()) {
                this.jessibuca.playVodResume()
            } else {
                if (this.playUrl) {
                    this.jessibuca.playVod(this.playUrl, {
                        useMSE: this.useMSE,
                        useWCS: this.useWCS,
                        useWasm: this.useWasm,
                        useSIMD: this.useSIMD,
                    }).then(() => {
                        ElMessage.success('playVod success');
                    }).catch((e) => {
                        ElMessage.error(`playVod error : ${toString(e)}`);
                    })
                    this.playType = 'playVod'
                } else {
                    ElMessage.error('play url is empty')
                }
            }
        },


        playVR() {
            if (this.jessibuca.isPlayVodPaused()) {
                this.jessibuca.playVodResume()
            } else {
                if (this.playUrl) {
                    // 重置下
                    this.jessibuca.once('start', () => {
                        this.jessibuca.enterVr();
                    })

                    this.jessibuca.playVod(this.playUrl, {
                        useMSE: this.useMSE,
                        useWCS: this.useWCS,
                        useWasm: this.useWasm,
                        useSIMD: this.useSIMD,
                        playVodMp4UseSrc:false,
                    }).then(() => {
                        ElMessage.success('playVR success');
                    }).catch((e) => {
                        ElMessage.error(`playVR error : ${toString(e)}`);
                    })
                    this.playType = 'playVR'
                } else {
                    ElMessage.error('play url is empty')
                }
            }
        },

        mute() {
            this.jessibuca.mute();
        },
        cancelMute() {
            this.jessibuca.cancelMute();
        },

        pause(isClear) {
            if (this.playType === 'playback') {
                this.jessibuca.playbackPause(isClear).then(() => {
                    console.log('playbackPause success');
                    this.playing = false;
                    this.err = "";
                    this.performance = "";
                }).catch((err) => {
                    console.log('playbackPause error', err);
                })
            } else if (this.playType === 'playVod' || this.playType === 'playVR') {
                this.jessibuca.playVodPause(isClear).then(() => {
                    console.log('playVodPause success');
                    this.playing = false;
                    this.err = "";
                    this.performance = "";
                }).catch((err) => {
                    console.log('playVodPause error', err);
                })
            } else {
                this.jessibuca.pause(isClear).then(() => {
                    console.log('pause success');
                    this.playing = false;
                    this.err = "";
                    this.performance = "";
                }).catch(() => {
                    console.log('pause error');
                });
            }

        },
        volumeChange() {
            this.jessibuca.setVolume(this.volume);
        },
        rotateChange() {
            this.jessibuca.setRotate(this.rotate);
        },

        mirrorRotateChange() {
            this.jessibuca.setMirrorRotate(this.mirrorRotate);

        },
        destroyPlayer() {
            return new Promise((resolve, reject) => {
                try {
                    if (this.jessibuca) {
                        this.jessibuca.destroy().then(() => {
                            this.jessibuca = null;
                            this.initPlayer();
                            this.playType = '';
                            resolve();
                        });
                    }
                } catch (e) {
                    console.error(e);
                    reject(e);
                }
            })
        },
        initPlayer() {
            this.create();
            // this.playType = '';
            this.playing = false;
            this.loaded = false;
            this.performance = "";
        },

        fullscreen() {
            this.jessibuca.setFullscreen(true);
        },

        clearView() {
            this.jessibuca.clearView();
        },

        startRecord() {
            const time = new Date().getTime();
            this.jessibuca.startRecord(time, this.recordType);
        },

        stopAndSaveRecord() {
            this.jessibuca.stopRecordAndSave();
        },
        stopAndSaveRecord2() {
            this.jessibuca.stopRecordAndSave('blob')

            this.jessibuca.once('recordBlob', (blob) => {
                !this.isDebug && console.log('recordBlob: ', blob);
            })
        },

        clearBufferDelay() {
            this.jessibuca.clearBufferDelay();
        },

        screenShot() {
            this.jessibuca.screenshot();
        },
        screenShotBlob() {
            const blob = this.jessibuca.screenshot('test', 'blob');
            console.log('screenShotBlob', blob);
        },
        screenShotBase64() {
            const base64 = this.jessibuca.screenshot('test', 'base64');
            console.log('screenShotBase64', base64);
        },

        screenshotWatermark1() {
            this.jessibuca.screenshotWatermark({
                text: {
                    content: 'jessibuca-pro',
                    fontSize: '40',
                    color: 'red'
                },
                right: 20,
                top: 40
            });
        },
        screenshotWatermark1Blob() {
            this.jessibuca.screenshotWatermark({
                image: {
                    src: '',
                    width: 60,
                    height: 60
                },
                right: 20,
                top: 20,
                type: 'blob'
            }).then((file) => {
                console.log('screenshotWatermark1Blob', file);
            }).catch((e) => {
                console.log('screenshotWatermark1Blob error', e);
                ElMessage.error(`截图失败：${toString(e)}`);
            });
        },
        screenshotWatermark2() {
            this.jessibuca.screenshotWatermark({
                image: {
                    src: '',
                    width: 60,
                    height: 60
                },
                right: 20,
                top: 20
            }).catch((e) => {
                console.log('screenshotWatermark2 error', e);
            });
        },
        screenshotWatermark2Blob() {
            this.jessibuca.screenshotWatermark({
                image: {
                    src: '',
                    width: 60,
                    height: 60
                },
                right: 20,
                top: 20,
                type: 'blob'
            }).then((file) => {
                console.log('screenshotWatermark2Blob', file);
            }).catch((e) => {
                console.log('screenshotWatermark2Blob error', e);
            });
        },

        restartPlay(type) {

            if (type === 'mse') {
                this.useWCS = false;
                this.useOffscreen = false;
                this.useSIMD = false;
            } else if (type === 'wcs') {
                this.useMSE = false
                this.useSIMD = false;
            } else if (type === 'offscreen') {
                this.useMSE = false
            } else if (type === 'simd') {
                this.useMSE = false;
                this.useWCS = false;
            } else {
                this.isFlv = false;
                this.isFmp4 = false;
                this.isHls = false;
                this.isPs = false;
                this.isTs = false;
                this.isNakedFlow = false;
                if (type === 'isNakedFlow') {
                    this.isNakedFlow = true;
                } else if (type === 'isFlv') {
                    this.isFlv = true;
                } else if (type === 'isFmp4') {
                    this.isFmp4 = true;
                } else if (type === 'isHls') {
                    this.isHls = true;
                } else if (type === 'isTs') {
                    this.isTs = true;
                } else if (type === 'isPs') {
                    this.isPs = true;
                }
            }
            this.replay();
        },

        replay() {
            this.destroyPlayer().then(() => {
                if (this.playType === 'play') {
                    this.play();
                } else if (this.playType === 'playback') {
                    this.playback();
                } else if (this.playType === 'playVod') {
                    this.playVod();
                } else if (this.playType === 'playVR') {
                    this.playVR()
                } else {
                    this.play();
                }
            });
        },

        changeBuffer() {
            this.jessibuca.setBufferTime(this.videoBuffer);
        },
        changeBufferDelay() {
            this.jessibuca.setBufferDelayTime(this.videoBufferDelay);
        },

        changeNetworkDelay() {
            this.jessibuca.setNetworkDelayTime(this.networkDelay);
        },

        scaleChange() {
            this.jessibuca.setScaleMode(this.scale);
        },

        renderDomChange() {
            this.replay();
        },
        playbackRateChange() {
            this.jessibuca.forward(this.playbackRate)
        },
        togglePerformance() {
            this.jessibuca.togglePerformancePanel(this.showPerformance);
        },

        toggleZoomOperate() {
            if (this.jessibuca.isZoomOpen()) {
                this.jessibuca.closeZoom();
            } else {
                this.jessibuca.openZoom();
            }
            this.toggleZoom = this.jessibuca.isZoomOpen();
        },
        startTalk() {
            const jessibuca = this.jessibuca;
            if (this.talkUrl) {
                jessibuca.startTalk(this.talkUrl, {
                    encType: this.talkEncType,
                    packetType: this.talkPacketType,
                    sampleBitsWidth: this.talkSampleBitsWidth,
                    sampleRate: this.talkSampleRate,
                    debug: true
                }).then(() => {

                }).catch((e) => {
                    console.error('start talk error', e);
                })
            }
        },
        stopTalk() {
            const jessibuca = this.jessibuca;
            jessibuca.stopTalk().then(() => {

            }).catch((e) => {
                console.error('stop talk error', e);
            });
        },
        talkGetVolume() {
            const jessibuca = this.jessibuca;
            jessibuca.getTalkVolume().then((volume) => {
                console.log('talk volume', volume);
            }).catch((e) => {
                console.error('get talk volume error', e);
            });
        },
        talkSetVolume() {
            const jessibuca = this.jessibuca;
            const talkVolume = parseFloat(this.talkVolume);
            jessibuca.setTalkVolume(talkVolume).then(() => {
                console.log('set talk volume success');
            }).catch((e) => {
                console.error('set talk volume error', e);
            });
        },
        openZoom() {
            const jessibuca = this.jessibuca;
            jessibuca.openZoom();

        },

        closeZoom() {
            const jessibuca = this.jessibuca;
            jessibuca.closeZoom();
        },

        handleAddCanvas(type) {
            const jessibuca = this.jessibuca;

            if (!jessibuca) {
                return
            }

            const x = Math.floor(Math.random() * 501) + 100; // 100-600
            const y = Math.floor(Math.random() * 101) + 100; // 100-200
            const x2 = Math.floor(Math.random() * 501) + 100; // 100-600
            const y2 = Math.floor(Math.random() * 101) + 100; // 100-200
            const width = Math.floor(Math.random() * 301) + 100; // 100-400
            const height = Math.floor(Math.random() * 201) + 100; // 100-300
            const width2 = Math.floor(Math.random() * 301) + 100; // 100-400
            const height2 = Math.floor(Math.random() * 201) + 100; // 100-300

            let contentList = [];
            if (type === 'text') {
                contentList.push({
                    type: 'text',
                    text: 'hello world 你好',
                    x,
                    y,
                    color: '#FF0000',
                    fontSize: 20
                })
                contentList.push({
                    type: 'text',
                    text: 'hello world2 你好2',
                    x: x2,
                    y: y2,
                    color: '#0000FF',
                    fontSize: 20
                })
            } else if (type === 'rect') {
                contentList.push({
                    type: 'rect',
                    x,
                    y,
                    width,
                    height,
                    color: '#FF0000',
                })
                contentList.push({
                    type: 'rect',
                    x: x2,
                    y: y2,
                    width: width2,
                    height: height2,
                    color: '#0000FF'
                })
            } else if (type === 'rect+text') {
                contentList.push({
                    type: 'rect',
                    x,
                    y,
                    width,
                    height,
                    color: '#FF0000',
                })
                contentList.push({
                    type: 'text',
                    text: 'hello world 你好',
                    x,
                    y,
                    color: '#FF0000',
                    fontSize: 20
                })
                contentList.push({
                    type: 'rect',
                    x: x2,
                    y: y2,
                    width,
                    height,
                    color: '#0000FF',
                    opacity: 0.5
                })
                contentList.push({
                    type: 'text',
                    text: 'hello world2 你好2',
                    x: x2,
                    y: y2,
                    color: '#0000FF',
                    fontSize: 20
                })
            }

            jessibuca.addContentToCanvas(contentList)
        },
        handleAddCanvasClean() {
            const jessibuca = this.jessibuca;

            if (!jessibuca) {
                return
            }

            jessibuca.clearContentToCanvas();
        },

        toggleControlBar() {
            this.jessibuca.toggleControlBar();
        },
    },
};
</script>
<style>
@keyframes ani {
    0% {
        transform: translatex(0);
    }
    100% {
        transform: translatex(-100%);
    }
}
</style>
<style scoped>
.root {
    display: flex;
    place-content: center;
    margin-top: 3rem;
    position: relative;
}

.container-shell {
    position: relative;
    backdrop-filter: blur(5px);
    background: hsla(0, 0%, 50%, 0.5);
    padding: 30px 4px 10px 4px;
    /* border: 2px solid black; */
    width: auto;
    position: relative;
    border-radius: 5px;
    box-shadow: 0 10px 20px;
}

.container-shell-title {
    position: absolute;
    color: darkgray;
    top: 4px;
    left: 10px;
    text-shadow: 1px 1px black;
}

.tag-version {
}

#container {
    background: rgba(13, 14, 27, 0.7);
    width: 900px;
    height: 568px;
}

.input {
    display: flex;
    align-items: center;
    margin-top: 3px;
    color: white;
    place-content: stretch;
    border-bottom: 1px solid #ccc;
    justify-content: start;
}

.input-wrap {
    justify-content: space-between;
}

.input2 {
    bottom: 0px;
}

.input input[type='input'] {
    flex: auto;
}

.input-annnie {
    position: relative;
    height: 20px;
    overflow: hidden;
}

.input-tips {
    position: absolute;
    width: 100%;
    text-align: right;
    top: 0;
    left: 0;
    animation: ani 20s linear infinite;
}

.err {
    position: absolute;
    top: 40px;
    left: 10px;
    color: red;
}

.span-row {
    display: inline-block;
    margin-right: 10px;
}

.option {
    position: absolute;
    top: 4px;
    right: 10px;
    display: flex;
    place-content: center;
    align-items: center;
    font-size: 12px;
}

.option span {
    color: white;
}

.page {
    background: url(/bg.jpg);
    background-repeat: no-repeat;
    background-position: top;
}

.show-message {
    position: fixed;
    z-index: 10000;
    left: 0;
    top: 31px;
    padding: 5px;
    font-size: 10px;
    background: rgba(0, 0, 0, 0.2);
    color: #fff;
}

@media (max-width: 720px) {
    #container {
        width: 90vw;
        height: 52.7vw;
    }
}
</style>
